package net.molchat.binroot;


import java.io.IOException;
import java.io.OutputStream;


public class RootWriter {

//==================================================================== Constants
public static final byte FLAG_CHILD = 1 << 0;
public static final byte FLAG_LAST = 1 << 1;
public static final byte FLAGS_NUM = 2; // Number of flags in the header


//======================================================================= Fields
private OutputStream stream;


//================================================================== Constructor
public RootWriter(OutputStream stream) {

	this.stream = stream;
}


//==================================================================== writeRoot
public void writeRoot(Root root) throws IOException {

	writeRoot(root, true);
}


private void writeRoot(Root root, boolean fLast) throws IOException {

	// Send header
	int header = root.nodeId << FLAGS_NUM;
	if (fLast) {
		header |= FLAG_LAST;
	}
	if (root.children != null) {
		header |= FLAG_CHILD;
	}
	writeVInt(header);

	// Send data
	if (root.data != null) {
		writeVInt(root.data.length);
		stream.write(root.data);
	} else {
		writeVInt(0); // Content length = 0
	}

	// Send children
	if (root.children != null) {
		int childNum = 0;
		int childLast = root.children.size() - 1;
		while (childNum <= childLast) {
			writeRoot(root.children.get(childNum), (childNum++ == childLast));
		}
	}
}


//==================================================================== writeVInt
/**
 * Writes variable length integer to output stream. Little-endian.
 * 
 * @throws IOException
 */
private void writeVInt(int number) throws IOException {

	if (number < 0) {
		throw new IllegalArgumentException("Number must be >= 0");
	}

	do {
		int toWrite = number & 0x7f;
		number >>>= 7;
		if (number > 0) {
			toWrite |= 0x80;
		}
		stream.write(toWrite);
	} while (number > 0);
}


}
